package com.lingjtx.auth.aop;

import com.lingjtx.auth.config.UserTypeContextWrapper;
import com.lingjtx.auth.handle.AuthHandle;
import com.lingjtx.common.core.ResponseResult;
import com.lingjtx.common.core.annotation.IgnoreLogin;
import com.lingjtx.common.core.constant.Const;
import com.lingjtx.common.core.token.AuthToken;
import com.lingjtx.common.core.token.IgnoreType;
import com.lingjtx.common.core.token.LoginMode;
import com.lingjtx.common.core.token.UserDetail;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.redis.service.IRedisService;
import com.lingjtx.common.security.limit.ApiContext;
import com.lingjtx.common.security.model.LoginPo;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Objects;

@Slf4j
@Component
@Aspect
@Order(1)
public class IgnoreLoginAspect {


    private final IRedisService redisService;
    private final UserTypeContextWrapper contextWrapper;

    public IgnoreLoginAspect(IRedisService redisService, UserTypeContextWrapper contextWrapper) {
        this.redisService = redisService;
        this.contextWrapper = contextWrapper;
    }

    @Around("@annotation(com.lingjtx.common.core.annotation.IgnoreLogin)")
    public Object interceptor(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        IgnoreLogin annotation = signature.getMethod().getAnnotation(IgnoreLogin.class);

        Object[] args = point.getArgs();

        if (Objects.nonNull(annotation) && !IgnoreType.IGNORE.equals(annotation.value())) {
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

            String userType = request.getHeader(Const.AuthTokenMap.USER_TYPE);
            if (IgnoreType.LOGOUT.equals(annotation.value()) || LoginMode.REFRESH_TOKEN.equals(annotation.model())) {
                String token = request.getHeader(Const.AuthTokenMap.AUTHORIZATION);
                UserDetail userDetail = AuthToken.getUser(token);
                if (Objects.nonNull(userDetail)) {
                    userType = userDetail.getUserType();
                }
            }

            if (StringUtil.isNotEmpty(args) && args[0] instanceof LoginPo loginPo) {
                loginPo.setUserType(userType);
                args[0] = loginPo;
            }

            // 4大账号体系，用户登录要求不一，统一走这一个aop，根据请求头来判断哪种用户类型走哪种策略
            // 具体的实现，操作数据库都在对应的AuthHandle实现类中
            AuthHandle auth = contextWrapper.getHandle(userType);

            ApiContext<ProceedingJoinPoint, HttpServletRequest> context = contextWrapper.create(auth);

            Object object = context.process(point, request, redisService);
            if (object instanceof ResponseResult) {
                return object;
            }
        }
        return point.proceed(args);
    }
}
